<?php
/**
 * PsiFramework
 *
 * Php Simple Framework
 *
 * PHP version 5.3
 *
 * @category  PsiFramework.Plugins.Form.Classes.DAO
 * @package   PsiFramework.Plugins.Form.Classes.DAO
 * @author    Remi San <remi.san@gmail.com>
 * @copyright 2011 Remi San
 * @license   http://creativecommons.org/licenses/by/3.0/  Creative Commons CC BY 3.0
 * @version   SVN: <svn_id>
 * @link      http://www.psiframework.com/phpdoc/classes/db_\PsiFramework\Plugins\Form\Classes\DAO\FieldTypeDAO.html
 */

namespace PsiFramework\Plugins\Form\Classes\DAO;

import("Classes.DAO.AbstractDAO");
import("Classes.Factory.DAOFactory");
import("Classes.Util.Plugin");
import("Classes.Util.Database.Query.SqlType");
import("Classes.Util.Parameters.ObjectParameters");
import("Classes.Util.Parameters.Object.AttributeParameters");
import("Classes.Util.Manager.PluginManager");
import("Plugins.Form.Classes.Model.FieldType");
import("Plugins.Form.Classes.DAO.FormResponseDAO");
import("Plugins.Form.Classes.Util.Json.JsonForm");
import("Plugins.Form.Classes.Util.Json.Elements.JsonFormInput");

use \PsiFramework\Classes\DAO\AbstractDAO;
use \PsiFramework\Classes\Model\Object;
use \PsiFramework\Classes\Factory\DAOFactory;
use \PsiFramework\Classes\Util\Plugin;
use \PsiFramework\Classes\Util\Database\Filters\QueryFilter;
use \PsiFramework\Classes\Util\Database\Query\SqlType;
use \PsiFramework\Classes\Util\Database\Query\SqlColumn;
use \PsiFramework\Classes\Util\Database\Query\SqlFunction;
use \PsiFramework\Classes\Util\Database\Query\SqlOperation;
use \PsiFramework\Classes\Util\Database\Query\SqlValue;
use \PsiFramework\Classes\Util\Parameters\ObjectParameters;
use \PsiFramework\Classes\Util\Parameters\Object\AttributeParameters;
use \PsiFramework\Classes\Util\Manager\PluginManager;
use \PsiFramework\Plugins\Form\Classes\Model\FieldType;
use \PsiFramework\Plugins\Form\Classes\DAO\FormResponseDAO;
use \PsiFramework\Plugins\Form\Classes\Util\Json\JsonForm;
use \PsiFramework\Plugins\Form\Classes\Util\Json\Elements\JsonFormInput;


/**
 * The FieldType Data Access Object
 *
 * This is the default class for the FieldType Data Access Object
 *
 * @category PsiFramework.Plugins.Form.Classes.DAO
 * @package  PsiFramework.Plugins.Form.Classes.DAO
 * @author   Remi San <remi.san@gmail.com>
 * @license  http://creativecommons.org/licenses/by/3.0/  Creative Commons CC BY 3.0
 * @link     http://www.psiframework.com/phpdoc/classes/db_\PsiFramework\Plugins\Form\Classes\DAO\FieldTypeDAO.html
 */
class FieldTypeDAO extends AbstractDAO
{
    /**
     * The singleton
     * 
     * @var FieldTypeDAO
     */
    protected static     $_singleton = null;
    
    /**
     * The current plugin
     * 
     * @var Plugin
     */
    protected /*Plugin*/ $_plugin = null;

    /**
     * FieldTypeDAO constructor
     * 
     * @param ObjectParameters $objectParameters The object parameters
     * 
     * @return FieldTypeDAO
     */
    protected function __construct(
        ObjectParameters $objectParameters=null
    )
    {
        parent::__construct($objectParameters);
        $this->_plugin
            = PluginManager::getInstance()->getPlugin('Form');
    }

    /**
     * The function that returns the table name based on a name
     * 
     * @param string $name The base name of the table
     * 
     * @return string
     */
    public static function getTableName(/*string*/ $name)
    {
        return ObjectParameters::getTableName($name).'_response' ;
    }

    /**
     * The function that returns the ObjectParameters that describe
     * the field type response table
     * 
     * @param string   $formName The name of the response table
     * @param JsonForm $jsonForm The JsonForm used to build
     *                            the response parameters
     * 
     * @return ObjectParameters
     */
    public function getResponseParametersFromJsonForm(
        /*string*/ $formName,
        JsonForm   $jsonForm
    )
    {
        $responseName = str_replace(' ', '', $formName).'Response' ;
        $responseTable = self::getTableName($formName);
        $responseParameters = self::getNewResponseParameters(
            $responseName,
            $responseTable
        );

        foreach ($jsonForm->getElements() as $field) {
            foreach ($field->getElements() as $element) {
                if ($element instanceof JsonFormInput) {
                    $name = $element->getName();
                    $columnName = $name ;
                    $nullable = ($element->isMandatory())?'false':'true' ;

                    $type = 'string' ;
                    $sqlLength = null ;
                    $sqlType = SqlType::$varchar ;
                    if ($element->isNumeric()) {
                        $type = 'int' ;
                        $sqlType = SqlType::$integer ;
                    } else if ($element->isFloat()) {
                        $type = 'float' ;
                        $sqlType = SqlType::$float ;
                    } else {
                        $sqlLength = '255' ;
                        if (!isNullOrEmptyString($element->getMaxLength())) {
                            $sqlLength = $element->getMaxLength();
                        }
                    }

                    switch($element->getInputType()) {
                    case 'hour':
                        $sqlLength = 10;
                        break;
                    case 'file':
                        if ($element->isImage()) {
                    	    $type = 'Image' ;
                        } else {
                            $type = 'File' ;
                        }
                    	$sqlType = SqlType::$text ;
                    	$sqlLength = null ;
                    	break;
                    case 'textarea':
                    case 'checkbox':
                    case 'radio':
                        $type = 'text' ;
                        $sqlType = SqlType::$text ;
                        $sqlLength = null ;
                        break;
                    case 'date':
                        $type = 'Date' ;
                        $sqlType = SqlType::$dateTime ;
                        $sqlLength = null ;
                        break;
                    }

                    $params = array(
                        'name'=>$name,
                        'column'=>$columnName,
                        'type'=>$type,
                        'sqlType'=>$sqlType,
                        'nullable'=>$nullable,
                        'primaryKey'=>'false'
                    );
                    if (!isNullOrEmptyString($sqlLength)) {
                        $params['length'] = $sqlLength ;
                    }

                    $responseParameters->addParameter(
                        new AttributeParameters($params)
                    );
                }
            }
        }

        return $responseParameters ;
    }

    /**
     * The function to retrieve the FieldType by partial name
     * 
     * @param string $partialName The partial name to find
     * 
     * @return array
     */
    public function retrieveByPartialName(/*string*/ $partialName)
    {

        $colNom = new SqlColumn('field_type_name');
        $value = '%' ;    if (!isNullOrEmptyString($partialName)) {
            $value .= mb_strtoupper($partialName, 'utf-8') . '%' ;
        }
        $sqlValue = new SqlValue($value);

        $upper = new SqlFunction('UPPER');
        $upper->addParameter($colNom);

        $like = new SqlOperation(SqlOperation::$like);
        $like->addParameter($upper);
        $like->addParameter($sqlValue);

        return $this->retrieveAll(new QueryFilter($like));

    }

    /**
     * The function to save a FieldType
     * 
     * @param \FieldType &$object            The object to save
     * @param bool       $performTransaction Does the save action
     *                                       need a transaction ?
     * @param bool       $checkSecurity      Does the save action
     *                                       need to check the security ?
     *                                      
     * @see \AbstractDAO::save()
     * 
     * @return bool
     */
    public function save(
        Object   &$object,
        /*bool*/ $performTransaction=true,
        /*bool*/ $checkSecurity=true,
        /*bool*/ $propagation=true
    )
    {
        if ($propagation) {
            //Retrieve the fields used by this field type
            $fieldDao = DAOFactory::getDAO('FormField');
            $fields = $object->getFields();
            
            if (!is_null($fields) && is_array($fields)) { 
                
                $forms = array();
                foreach ($fields as $field) {
                    $fieldForms = $field->getForms();
                    foreach ($fieldForms as $formFieldLink) {
                        //Retrieve the forms used by the fields used by the field type
                        $form = $formFieldLink->getForm();
                        $forms[$form->getName()] = $form;
                    }
                }
                
                //Delete the views
                foreach ($forms as $formName=>$form) {
                    $formResponseDao = FormResponseDAO::getInstance($form->getResponseParameters());
                    $formResponseDao->deleteTable();
                }
            }

        }
        
        $formResponseDao = FormResponseDAO::getInstance($object->getResponseParameters());
        $formResponseDao->createTable();
        
        if ($performTransaction) {
            $this->_database->startTransaction();
        }

        $this->_plugin->addObjectParameter($object->getResponseParameters());
        $ok = parent::save($object, false, $checkSecurity);

        if ($ok && $propagation) {
            if (!is_null($fields)) {
                foreach ($fields as $field) {
                    $ok = $fieldDao->save($field, false, $checkSecurity);
                    if (!$ok) {
                        break;
                    }
                }
            }
        }

        if ($performTransaction) {
            if ($ok) {
                $this->_database->commit();
            } else {
                $this->_database->rollback();
            }
        }

        return $ok ;
    }

    /**
     * The function to delete a FieldType
     * 
     * @param \FieldType &$object            The object to delete
     * @param bool       $performTransaction Does the delete action
     *                                       need a transaction ?
     * @param bool       $checkSecurity      Does the delete action
     *                                       need to check the security ?
     *                                      
     * @see \AbstractDAO::delete()
     * 
     * @return bool
     */
    public function delete(
        Object   &$object,
        /*bool*/ $performTransaction=true,
        /*bool*/ $checkSecurity=true
    )
    {

        $ok = true ;

        $formResponseDao = FormResponseDAO::getInstance(
            $object->getResponseParameters()
        );
        $formResponseDao->deleteTable();

        if ($performTransaction) {
            $this->_database->startTransaction();
        }

        $fieldDao = DAOFactory::getDAO('FormField');

        $fields = $object->getFields();
        if (!is_null($fields)) {
            foreach ($fields as $field) {
                $ok = $fieldDao->delete($field, false, $checkSecurity);
                if (!$ok) {
                    break;
                }
            }
        }

        if ($ok) {
            $ok = parent::delete($object, false, $checkSecurity);
        }

        if ($performTransaction) {
            if ($ok) {
                $this->_database->commit();
            } else {
                $this->_database->rollback();
            }
        }

        return $ok ;
    }

    /**
     * Creates the ObjectParameters base object for a field type response
     *
     * @param string $name      The name of the object
     * @param string $tableName The name of the table
     * 
     * @return ObjectParameters The ObjectParameters base
     */
    public static function getNewResponseParameters(
        /*string*/ $name,
        /*string*/ $tableName
    )
    {
        $responseParameters = new ObjectParameters(
            $name,
            'Plugins.Form.Classes.Model.FormResponse',
            'Plugins.Form.Classes.DAO.FormResponseDAO',
            $tableName,
            'form',
            array()
        );
        $responseParameters->addParameter(
            new AttributeParameters(
                array(
                    'name'=>'formResponseId',
                    'column'=>$tableName.'_id',
                    'type'=>'int',
                    'sqlType'=>SqlType::$integer,
                    'nullable'=>'false',
                    'primaryKey'=>'true'
                )
            )
        );
        $responseParameters->addParameter(
            new AttributeParameters(
                array(
                    'name'=>'user',
                    'column'=>'user_id',
                    'type'=>'User',
                    'sqlType'=>SqlType::$integer,
                    'nullable'=>'false',
                    'primaryKey'=>'true'
                )
            )
        );
        $responseParameters->addParameter(
            new AttributeParameters(
                array(
                    'name'=>'field',
                    'column'=>'field_id',
                    'type'=>'FormField',
                    'sqlType'=>SqlType::$integer,
                    'nullable'=>'false',
                    'primaryKey'=>'true'
                )
            )
        );
        $responseParameters->addParameter(
            new AttributeParameters(
                array(
                    'name'=>'form',
                    'column'=>'form_id',
                    'type'=>'Form',
                    'sqlType'=>SqlType::$integer,
                    'nullable'=>'false',
                    'primaryKey'=>'true'
                )
            )
        );
        $responseParameters->addParameter(
            new AttributeParameters(
                array(
                    'name'=>'modificationDate',
                    'column'=>'modification_date',
                    'type'=>'Date',
                    'sqlType'=>SqlType::$dateTime
                )
            )
        );
        return $responseParameters ;
    }

    function retrieveByResponseName(/*string*/ $name)
    {
        $colNom = new SqlColumn("form_response_name");
        $sqlValue = new SqlValue($name);
        $op = new SqlOperation(SqlOperation::$equal);
    
        $op->addParameter($colNom);
        $op->addParameter($sqlValue);
    
        $result = $this->retrieveAll(new QueryFilter($op));
    
        if (count($result)==1) {
            return $result[0] ;
        } else {
            return null ;
        }
    }
    
    /**
     * The function to call instead of the constructor.
     *
     *@param ObjectParameters $objectParameters the object parameters 
     *                                          for FieldType
     *
     * @return FieldTypeDAO instance
     */
    public static function getInstance(ObjectParameters $objectParameters)
    {

        if (self::$_singleton==null) {
            self::$_singleton = new FieldTypeDAO($objectParameters);
        }

        return self::$_singleton;
    }
}
